package ltd.newbee.mall.config.aop;

import cn.hutool.core.util.CharsetUtil;
import cn.hutool.crypto.digest.DigestUtil;
import lombok.extern.slf4j.Slf4j;
import ltd.newbee.mall.common.NewBeeMallException;
import ltd.newbee.mall.config.RedisCache;
import ltd.newbee.mall.config.annotation.PreventSubmit;
import ltd.newbee.mall.util.SpringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.util.StreamUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

/**
 * @description:
 * @author: qzx
 * @date: 2022-08-13 16:33
 * @version: 1.0
 */
@Component
@Aspect
@Slf4j
public class PreventSubmitAspect {

    @Resource
    private RedisCache redisCache;

    @Around(value = "@annotation(submit)")
    public Object onPreventSubmit(ProceedingJoinPoint pjp, PreventSubmit submit) throws Throwable {
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();
        String className = pjp.getTarget().getClass().getName();
        String methodName = method.getName();
        HttpServletRequest request = SpringUtils.currentRequest();
        String params = StreamUtils.copyToString(request.getInputStream(), CharsetUtil.CHARSET_UTF_8);
        // 类名 + 方法名 + 参数
        String clientId = DigestUtil.md5Hex(className + methodName + params);
        String key = redisCache.getCacheObject(submit.key() + clientId);
        log.info("类名 class = {}, 方法名 method = {}, md5签名 client = {}", className, methodName, clientId);
        if (redisCache.lock(key)) {
            NewBeeMallException.fail("重复请求，请稍后再试");
        }
        redisCache.expire(key, submit.expireTime());
        return pjp.proceed(pjp.getArgs());
    }
}
